<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="fqhB5" id="fqhB5"><span data-lake-id="u7c92dea6" id="u7c92dea6">典型回答</span></h1>
  <p data-lake-id="u8047b454" id="u8047b454"><br></p>
  <p data-lake-id="ufb1e3392" id="ufb1e3392"><span data-lake-id="u4336c090" id="u4336c090">通过AOP即可实现，通过AOP对Bean进行代理，在每次执行方法前或者后进行几次计数统计。这个主要就是考虑好如何避免并发情况下不准，以及如何使用AOP实现代理。</span></p>
  <p data-lake-id="ud0be088a" id="ud0be088a"><span data-lake-id="ud60714d1" id="ud60714d1">​</span><br></p>
  <p data-lake-id="u1f1f065b" id="u1f1f065b"><span data-lake-id="u80a1f5c5" id="u80a1f5c5">主要的代码如下：</span></p>
  <p data-lake-id="u422ad99a" id="u422ad99a"><span data-lake-id="u0b8b4804" id="u0b8b4804">​</span><br></p>
  <p data-lake-id="u5a981897" id="u5a981897"><span data-lake-id="udf9ba0c4" id="udf9ba0c4">首先我们先自定义一个注解，有了这个注解之后，我们可以在想要统计的方法上加上这个注解：</span></p>
  <p data-lake-id="ua52d233d" id="ua52d233d"><span data-lake-id="u57338005" id="u57338005">​</span><br></p>
  <pre lang="java"><code>
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Hollis
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodCallCount {
    
}
</code></pre>
  <p data-lake-id="u9606890f" id="u9606890f"><br></p>
  <p data-lake-id="u6fedf17f" id="u6fedf17f"><span data-lake-id="u853e2028" id="u853e2028">接下来定义一个切面，来对这个注解进行增强处理：</span></p>
  <p data-lake-id="ubfadf170" id="ubfadf170"><span data-lake-id="u6e079f56" id="u6e079f56">​</span><br></p>
  <pre lang="java"><code>
@Aspect
@Component
public class MethodCallCounterAspect {

	private Map&lt;String, AtomicInteger&gt; methodCallCountMap = new ConcurrentHashMap&lt;&gt;();

    @Around("@annotation(com.hollis.chuang.java.bagu.MethodCallCount)")
    public Object facade(ProceedingJoinPoint pjp) throws Exception {

        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        String methodName = method.getName();

        try{
            return pjp.proceed();
        } catch (Throwable e) {
            //异常处理
        } finally{
            //计数+1
            AtomicInteger counter = methodCallCountMap.computeIfAbsent(methodName, k -&gt; new AtomicInteger(0));
            counter.incrementAndGet();
        }
    }

    public int getMethodCallCount(String methodName) {
        AtomicInteger counter = methodCallCountMap.get(methodName);
        return (counter != null) ? counter.get() : 0;
    }
}
</code></pre>
  <p data-lake-id="u80ff7642" id="u80ff7642"><br></p>
  <p data-lake-id="u5887ba1c" id="u5887ba1c"><br></p>
  <p data-lake-id="u8b045713" id="u8b045713"><span data-lake-id="ud97e278b" id="ud97e278b">有了以上注解和切面后，只需要在我们想要统计的方法上使用该注解就行了：</span></p>
  <p data-lake-id="u689a72e1" id="u689a72e1"><span data-lake-id="u3dd1eeb5" id="u3dd1eeb5">​</span><br></p>
  <pre lang="java"><code>
@Service
public class HollisTestServiceImpl implements HollisTestService {

 
    @MethodCallCount
    @Override
    public HollisTestResponse test(HollisTestRequest hollisTestRequest) {
        
    }
</code></pre>
  <p data-lake-id="ud8d57b0d" id="ud8d57b0d"><br></p>
  <p data-lake-id="udb92a20d" id="udb92a20d"><br></p>
  <p data-lake-id="u47c790a9" id="u47c790a9"><span data-lake-id="u7b77a1a1" id="u7b77a1a1">以上，当test方法被调用时，就会自动统计调用次数。</span></p>
  <p data-lake-id="u5e469d44" id="u5e469d44"><span data-lake-id="u7ca95894" id="u7ca95894">​</span><br></p>
  <p data-lake-id="ua6900ada" id="ua6900ada"><span data-lake-id="u363d7485" id="u363d7485">但是需要注意的是，这个统计结果只在内存中有效，如果应用发生重启，就会归零了。如果想要持久化保存，就需要考虑持久化存储了，如存在mysql或者redis中。</span></p>
  <p data-lake-id="u35e84c9c" id="u35e84c9c"><span data-lake-id="u876f0e44" id="u876f0e44">​</span><br></p>
  <p data-lake-id="ua0ce46a0" id="ua0ce46a0"><span data-lake-id="u3bd08470" id="u3bd08470">另外，如果并发特别高，对统计结果要求没那么精确， 可以用LongAdder替代AtomicInteger</span></p>
 </body>
</html>